package dubbot

import (
	"fmt"
	hessian "github.com/apache/dubbo-go-hessian2"
	"github.com/hyperway/pkg/component"
	"github.com/hyperway/pkg/constant"
	"github.com/hyperway/pkg/helper"
	values2 "github.com/hyperway/pkg/helper/values"
	"github.com/hyperway/pkg/serialize"
	"github.com/hyperway/pkg/transporter"
)

func GetDubboValue(ctx component.WebContext, argument component.ServiceArgument) (interface{}, error) {
	v := transporter.GetWebValue(ctx, argument)
	if helper.IsNil(v) && argument.DefaultValue != "" {
		v = argument.DefaultValue
	}
	return Encoder4Ctx(argument.ClassType, v)
}

func Encoder(values ...interface{}) interface{} {
	size := len(values)
	encodeValues := make([]hessian.Object, size)
	for i := 0; i < size; i++ {
		encodeValues[i] = hessian.Object(values[i])
	}
	return encodeValues
}

func Encoder4Ctx(t string, v interface{}) (interface{}, error) {
	return Encode(v, t)
}

// Encoder4Values encode values to hessian.Object slice
// types: the types of values
// values: the values to encode, the length of types and values must be equal
func Encoder4Values(types []string, values ...interface{}) (interface{}, error) {
	if len(types) != len(values) {
		return nil, fmt.Errorf("the length of types and values must be equal")
	}
	size := len(types)
	encodeValues := make([]hessian.Object, 0, size)
	for i := 0; i < size; i++ {
		encodeValue, err := Encode(values[i], types[i])
		if err != nil {
			return nil, err
		}
		encodeValues = append(encodeValues, encodeValue)
	}
	return encodeValues, nil
}

// Encode encode value to hessian.Object
// targetType: the type of value
// value: the value to encode
func Encode(value interface{}, targetType string) (interface{}, error) {
	switch targetType {
	default:
		var arbitraryMap interface{}
		err := serialize.JSONToObject([]byte(values2.String(value)), &arbitraryMap)
		return arbitraryMap, err
	case constant.JavaTypeByte:
		return hessian.Object(values2.Byte(value)), nil
	case constant.JavaTypeBoolean:
		return hessian.Object(values2.Bool(value)), nil
	case constant.JavaTypeFloat:
		return hessian.Object(values2.Float32(value)), nil
	case constant.JavaTypeDouble:
		return hessian.Object(values2.Float64(value)), nil
	case constant.JavaTypeShort:
		return hessian.Object(values2.Int16(value)), nil
	case constant.JavaTypeInteger:
		return hessian.Object(values2.Int32(value)), nil
	case constant.JavaTypeLong:
		return hessian.Object(values2.Int64(value)), nil
	case constant.JavaTypeString:
		return values2.String(value), nil
		//case constant.JavaTypeList:
		//	return values.SliceAny(value), nil
		//case constant.JavaTypeMap:
		//	return values.Map(value), nil
	}
	return nil, fmt.Errorf("unknown backend param type: %s", targetType)
}
